package net.quanter.shield.dubbo.filter;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import cn.hutool.core.collection.CollectionUtil;
import net.quanter.shield.common.dto.context.InvocationContextDTO;
import net.quanter.shield.common.dto.context.InvocationDTO;
import net.quanter.shield.common.enums.context.InvocationType;
import net.quanter.shield.dubbo.interceptor.DubboInvocationInterceptor;
import net.quanter.shield.utils.bean.BeanUtils;
import net.quanter.shield.utils.invocation.InvocationUtil;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

/***
 *
 * created on 2020-10-09
 * @author 王老实
 * @see DubboInvocationInterceptor
 *
 */
@Activate(group = CommonConstants.CONSUMER)
public class DubboDebugConsumerFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        InvocationContextDTO contextDTO = InvocationUtil.getContext();
        InvocationDTO invocationDTO = null;
        if (contextDTO != null) {
            invocationDTO = new InvocationDTO();
            invocationDTO.setIndex(contextDTO.addAndGet(1));
            invocationDTO.setServiceName(invocation.getServiceName());
            invocationDTO.setMethodName(invocation.getMethodName());
            invocationDTO.setArgs(BeanUtils.clones(invocation.getArguments()));
            invocationDTO.setType(InvocationType.DUBBO);
            //往下传递调用链
            invocation.setAttachment("DubboContextDTO", contextDTO);
        }
        long begin = System.currentTimeMillis();
        if (contextDTO == null) {
            return invoker.invoke(invocation);
        } else {
            Result result = null;
            try {
                result = invoker.invoke(invocation);
            } catch (Throwable e) {
                invocationDTO.setE(e);
            }
            invocationDTO.setRt(System.currentTimeMillis() - begin);
            if (result != null && result.getValue() != null) {
                Object resultValue = result.getValue();
                invocationDTO.setResult(BeanUtils.clone(resultValue));
            }
            if (result != null) {
                List<InvocationDTO> chain = (List<InvocationDTO>) result.getObjectAttachment("dubboChain");
                if (CollectionUtil.isNotEmpty(chain)) {
                    invocationDTO.setChain(chain);
                    Integer maxIndex = chain.stream().map(InvocationDTO::getIndex).max(Integer::compareTo).get();
                    contextDTO.setAndGet(maxIndex);
                }
            }
            InvocationUtil.add(invocationDTO);
            return result;
        }
    }
}
